package com.zhou.cloud.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zhou.cloud.entry.DemoHttpClient;
import com.zhou.cloud.entry.DemoHttpConst;
import com.zhou.cloud.entry.DemoHttpRespStatus;
import com.zhou.cloud.service.IProductService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.HttpEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.*;

import java.lang.ref.ReferenceQueue;
import java.text.MessageFormat;

/**
 * @descrition: 商品服务接口
 * @author: zhouyongjun
 * @date: 2022/11/22
 **/
@Slf4j
@RestController
@RequestMapping("/product")
public class ProductController {
    //锁生成访问客户端
    @Autowired
    @Qualifier("lockHttpClient")
    DemoHttpClient lockHttpClient;

    @Autowired
    IProductService productService;
    @GetMapping("/get/all")
    public JSONObject getAll()
    {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put(DemoHttpConst.RESP_CODE, DemoHttpRespStatus.OK);
        jsonObject.put(DemoHttpConst.RESP_DATA,productService.getAllList());
        return jsonObject;
    }

    @GetMapping("/get/{pid}")
    public JSONObject get(@PathVariable("pid") Long pid)
    {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put(DemoHttpConst.RESP_CODE, DemoHttpRespStatus.OK);
        jsonObject.put(DemoHttpConst.RESP_DATA,productService.get(pid));
        return jsonObject;
    }

    /**
    * @Description: 数据库中售卖
    * @Params: 
    * @Returns:
    * @Author: zhouyongjun
    * @Date Created in 2022/11/28 14:40
     */
    @PutMapping("/sold/{pid}")
    @SentinelResource(value = "sold",fallback = "soldFailBack",blockHandler = "soldFailBack")
    public JSONObject sold(@PathVariable("pid") Long pid, Integer delNum)
    {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put(DemoHttpConst.RESP_CODE, DemoHttpRespStatus.OK);
        if (!productService.sold(pid,delNum))
        {
            jsonObject.put(DemoHttpConst.RESP_CODE, DemoHttpRespStatus.FAIL);
            jsonObject.put(DemoHttpConst.RESP_MSG,"数量不足");
        }
        return jsonObject;
    }

    /**
    * @Description: 从缓存中售卖
    * @Params: 
    * @Returns: 
    * @Author: zhouyongjun
    * @Date Created in 2022/11/28 14:40
     */
    @PutMapping("/sold/cache/{pid}")
    @SentinelResource(value = "sold-cache",fallback = "soldFailBack",blockHandler = "soldFailBack")
    public JSONObject soldFromCache(@PathVariable("pid") Long pid, Integer delNum)
    {
        String lockKey = "product-sold";
        String lockRequestId = "key-"+pid;
        lock(lockKey,lockRequestId);
        JSONObject jsonObject;
        try {
            jsonObject = new JSONObject();
            jsonObject.put(DemoHttpConst.RESP_CODE, DemoHttpRespStatus.OK);
            if (!productService.soldFromCache(pid,delNum))
            {
                jsonObject.put(DemoHttpConst.RESP_CODE, DemoHttpRespStatus.FAIL);
                jsonObject.put(DemoHttpConst.RESP_MSG,"数量不足");
            }
        } finally {
            releaseLock(lockKey,lockRequestId);
        }
        return jsonObject;
    }

    private void releaseLock(String lockKey, String requestId) {
        String url = MessageFormat.format("{0}lock/redis/release/{1}/{2}",lockHttpClient.getUrl(),lockKey,requestId);
        MultiValueMap<String,String> requestParam = new LinkedMultiValueMap<>();
        requestParam.add("lockKey",lockKey);
        requestParam.add("lockKey",requestId);
        lockHttpClient.getRestTemplate().delete(url);
    }

    private boolean lock(String lockKey, String requestId) {
        String url = MessageFormat.format("{0}/lock/redis/try",lockHttpClient.getUrl());
        MultiValueMap<String,String> requestParam = new LinkedMultiValueMap<>();
        requestParam.add("lockKey",lockKey);
        requestParam.add("requestId",requestId);
        requestParam.add("expireMillis",String.valueOf(30000));
        ResponseEntity<JSONObject> responseEntity = lockHttpClient.getRestTemplate().postForEntity(url,requestParam,JSONObject.class);
        JSONObject responseBody = responseEntity.getBody();
        if (DemoHttpRespStatus.OK.name().equals(responseBody.get(DemoHttpConst.RESP_CODE)))
        {
            return true;
        }
        return false;
    }

    public JSONObject soldFailBack(Throwable e) {
        log.error("",e);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put(DemoHttpConst.RESP_CODE, DemoHttpRespStatus.FAIL);
        jsonObject.put(DemoHttpConst.RESP_MSG,"出售失败");
        return jsonObject;
    }
    
}
